/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package wifipositioner;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.pi4.locutil.MACAddress;
import org.pi4.locutil.trace.SignalStrengthSamples;
import org.pi4.locutil.trace.TraceEntry;

/**
 *
 * @author hh
 */
public class FingerPrintingNN implements IFingerprintWifiPositioner {
    
    public ArrayList<PositionCalculationResult> CalculatePositions(List<TraceEntry> offlineTraces, List<TraceEntry> onlineTraces)
    {
        HashMap<MACAddress, ArrayList<TraceEntry>> index = new HashMap<>();
                        
        ArrayList<PositionCalculationResult> resultList = new ArrayList<>();

        // Init HashMap with macadresses as keys and a list of entries that 'sees' the macadress as the value
        for(TraceEntry entry: offlineTraces) 
        {
            SignalStrengthSamples s = entry.getSignalStrengthSamples();
            for(MACAddress m : s.getSortedAccessPoints()) {
                if(index.containsKey(m) == false){
                    index.put(m, new ArrayList<TraceEntry>());
                }
                index.get(m).add(entry);
            }			
        }
		
        
        // Find the best fitted offline entry for all the online entries
        for(TraceEntry entry: onlineTraces) 
        {
            HashSet<TraceEntry> entries = new HashSet();
            // Get all the offline entries that 'sees' the same AP's as the current online entry
            for(MACAddress m : entry.getSignalStrengthSamples().getSortedAccessPoints()) 
            {
                if(index.containsKey(m))
                {
                    for(TraceEntry offlineEntry : index.get(m)) 
                    {
                        if(entries.contains(offlineEntry) == false) 
                            entries.add(offlineEntry);
                    }
                }
            }

            double minDistance = Double.MAX_VALUE;
            TraceEntry bestEntry = null;
            
            // Get the offline entry with the least euclidean signal strength distance 
            for(TraceEntry offline : entries) 
            {
                double distance = DistanceCalculator.calcDistance(offline, entry, 6);
                if(distance < minDistance) 
                {
                    bestEntry = offline;
                    minDistance = distance;
                }
            }
            
            // Add the best fitted offline entry and the online entry to the list
            PositionCalculationResult result = new PositionCalculationResult(bestEntry.getGeoPosition(), entry.getGeoPosition());
            resultList.add(result); 
            
            //System.out.println("Estimated position: " + bestEntry.getGeoPosition().toString() + " True position: "+entry.getGeoPosition().toString());
        } 
        return resultList;
    }
    
}
